package com.time.store.auth.service;


import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.util.BeanUtil;
import com.time.store.auth.entity.base.ActiveUser;
import com.time.store.auth.entity.bo.Permission;
import com.time.store.auth.entity.bo.Users;
import com.time.store.auth.entity.dto.*;
import com.time.store.auth.entity.vo.LoginRes;
import com.time.store.auth.mapper.UsersMapper;
import com.time.store.core.config.AuthConfig;
import com.time.store.core.consts.RedisKeyConst;
import com.time.store.core.util.AssertUtil;
import com.time.store.core.util.AuthUtil;
import com.time.store.store.entity.bo.StoreInfo;
import com.time.store.store.service.StoreInfoService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author 时间
 * @since 2021-04-25
 */
@Service
public class UsersService extends ServiceImpl<UsersMapper, Users> implements IService<Users> {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private ModulesService modulesService;
    @Autowired
    private PermissionService permissionService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuthConfig authConfig;
    @Autowired
    private StoreInfoService storeInfoService;

    public LoginRes login(LoginUserReq loginUserReq) {
        Users users = getUserByLoginName(loginUserReq.getName());
        AssertUtil.notNull(users, "未获取到用户:" + loginUserReq.getName());
        AssertUtil.isTrue(passwordEncoder.matches(loginUserReq.getPassword(), users.getPassword()), "密码错误:" + loginUserReq.getName());
        AuthUtil.setRequestStoreId(users.getStoreId());
        //模块
        List<Tree<Integer>> modules = modulesService.getModulesByUserId(users.getId());
        //资源
        List<Permission> permissions = permissionService.getPermissionByUserId(users.getId());
        // 店铺信息
        StoreInfo store = null;
        if (ObjectUtil.isNotNull(users.getStoreId()))
            store = storeInfoService.getById(users.getStoreId());

        // 更改最后登录时间
        users.setLastLoginTime(LocalDateTime.now());
        updateById(users);

        ActiveUser activeUser = new ActiveUser();
        activeUser.setActiveUsers(users);
        activeUser.setMenu(modules);
        activeUser.setPermissions(permissions);
        activeUser.setStoreInfo(store);
        // token和刷新token逻辑处理
        String token = UUID.randomUUID().toString();
        String refreshToken = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(RedisKeyConst.AUTH + token, activeUser, Duration.ofSeconds(authConfig.getExpire()));
        redisTemplate.opsForValue().set(RedisKeyConst.REFRESH + refreshToken, loginUserReq, Duration.ofSeconds(authConfig.getRefreshExpire()));
        LoginRes loginRes = new LoginRes();
        loginRes.setToken(token);
        loginRes.setRefreshToken(refreshToken);
        Long expire = redisTemplate.getExpire(RedisKeyConst.AUTH + token);
        loginRes.setExpire(expire);
        return loginRes;
    }

    /**
     * 根据loginName获取
     *
     * @param loginName
     * @return
     */
    public Users getUserByLoginName(String loginName) {
        return baseMapper.selectByLoginName(loginName);
    }

    public LoginRes refreshToken(String refreshToken) {
        AssertUtil.isTrue(!redisTemplate.hasKey(RedisKeyConst.AUTH + AuthUtil.getToken()), "token没有过期,请勿刷新token");
        AssertUtil.isTrue(redisTemplate.hasKey(RedisKeyConst.REFRESH + refreshToken), "刷新token已过期,请重新登录");
        LoginUserReq loginUserReq = (LoginUserReq) redisTemplate.opsForValue().get(RedisKeyConst.REFRESH + refreshToken);
        return login(loginUserReq);
    }

    /**
     * 查询用户list
     *
     * @param users
     * @return
     */
    public Page<Users> pageUser(UserPageReq users) {
        IPage<UserPageReq> iPage = new Page<>(users.getCurrent(), users.getSize());
        return baseMapper.pageUser(iPage, users);
    }

    /**
     * 增加用户
     */
    public int save(AddUserReq addUserReq) {
        Users users = new Users();
        BeanUtils.copyProperties(addUserReq, users);
        users.setPassword(passwordEncoder.encode(users.getPassword()));
        return baseMapper.insert(users);

    }

    /**
     * 修改用户
     */
    public int updateUser(UpdateUserReq updateUserReq) {
        Users users = new Users();
        BeanUtils.copyProperties(updateUserReq, users);
        return baseMapper.updateById(users);

    }

    /**
     * 修改密码
     */
    public void updatePassword(UpdatePasswordReq updatePasswordReq) {
        Users user = baseMapper.selectById(AuthUtil.getCurrUserId());
        AssertUtil.isTrue(passwordEncoder.matches(user.getPassword(), updatePasswordReq.getPassword()), "密码错误:");
        Users u = new Users();
        u.setId(user.getId());
        u.setPassword(passwordEncoder.encode(updatePasswordReq.getNewPassword()));
        updateById(u);

    }

    /**
     * 个人设置
     *
     * @param settingUserDTO
     */
    public void setting(SettingUserDTO settingUserDTO) {
        Users users = new Users();
        BeanUtils.copyProperties(settingUserDTO, users);
        users.setId(AuthUtil.getCurrUserId());
        updateById(users);
    }
}
